/*
* LongestRunOfOnes.cpp
* Last edited: 21.07.2014
* Author: David Noack
*/
#include "LongestRunOfOnes.h"

//Inittialize the base class with the input data
LongestRunOfOnes::LongestRunOfOnes(bool* bitArray, int bitArraySize) : NistTest(bitArray, bitArraySize){};


double LongestRunOfOnes::execute(int size)
{
	n = size;
	int oneCounter = 0;
	int maxCount = 0;
	int numberOfClasses = 0;
	double numerator = 0.0;
	double denominator = 0.0;

	if (size < 128)
	{
		std::cout << "Error: The number of bits to test must be at least 128.";
	}
	else
	{
		if (size < 6272)
		{
			numberOfClasses = 4;
			v = new v_class[numberOfClasses];

			v[0].value = 1;
			v[0].pi = 0.2148;
			v[0].count = 0;

			v[1].value = 2;
			v[1].pi = 0.3672;
			v[1].count = 0;

			v[2].value = 3;
			v[2].pi = 0.2305;
			v[2].count = 0;

			v[3].value = 4;
			v[3].pi = 0.1875;
			v[3].count = 0;

			blockSize = 8;

		}
		else
		{
			if (size < 750000)
			{
				numberOfClasses = 6;
				v = new v_class[numberOfClasses];

				v[0].value = 4;
				v[0].pi = 0.1174;
				v[0].count = 0;

				v[1].value = 5;
				v[1].pi = 0.2430;
				v[1].count = 0;

				v[2].value = 6;
				v[2].pi = 0.2493;
				v[2].count = 0;

				v[3].value = 7;
				v[3].pi = 0.1752;
				v[3].count = 0;

				v[4].value = 8;
				v[4].pi = 0.1027;
				v[4].count = 0;

				v[5].value = 9;
				v[5].pi = 0.1124;
				v[5].count = 0;

				blockSize = 128;

			}
			else
			{
				numberOfClasses = 7;
				v = new v_class[numberOfClasses];

				v[0].value = 10;
				v[0].pi = 0.0882;
				v[0].count = 0;

				v[1].value = 11;
				v[1].pi = 0.2092;
				v[1].count = 0;

				v[2].value = 12;
				v[2].pi = 0.2483;
				v[2].count = 0;

				v[3].value = 13;
				v[3].pi = 0.1933;
				v[3].count = 0;

				v[4].value = 14;
				v[4].pi = 0.1208;
				v[4].count = 0;

				v[5].value = 15;
				v[5].pi = 0.0675;
				v[5].count = 0;

				v[6].value = 16;
				v[6].pi = 0.0727;
				v[6].count = 0;

				blockSize = 10000;
			}
		}
	}

	numberOfblocks = size / blockSize;


	for (int i = 0; i < numberOfblocks; i++)
	{
		maxCount = 0;
		oneCounter = 0;

		for (int j = 0; j < blockSize; j++)
		{
			if (bitArray[j + i*blockSize] == 1)
				oneCounter++;
			else
			{
				if (oneCounter > maxCount)
					maxCount = oneCounter;
				oneCounter = 0;
			}
		}
		if (oneCounter > maxCount)
			maxCount = oneCounter;


		if (maxCount < v[0].value)
			v[0].count++;
		else
		{
			for (int b = 0; b < numberOfClasses; b++)
			{
				if (maxCount == v[b].value)
				{
					v[b].count++;
					break;
				}
					
			}

			if (maxCount > v[numberOfClasses-1].value)
				v[numberOfClasses-1].count++;
		}

	}

	//compute chi 2 - STEP 3
	for (int i = 0; i < numberOfClasses; i++)
	{
		numerator = (v[i].count - numberOfblocks*v[i].pi);
		denominator = numberOfblocks * v[i].pi;

		chi_sqr += ((numerator*numerator) / denominator);
	}

	//compute P_value - STEP 4

	p_value = boost::math::gamma_q((numberOfClasses)/2, chi_sqr / 2);


	return p_value;

}
